原型链了解(推荐 Es6,过时禁止使用的)
首先了解下什么是原型链,JavaScript 中所有的对象都有一个内置属性,称为它的 prototype(原型)。它本身是一个对象,故原型对象也会有它自己的原型,逐渐构成了原型链。原型链终止于拥有 null 作为其原型的对象上。
备注:
指向对象原型的属性并不是 prototype。它的名字不是标准的,但实际上所有浏览器都使用 __proto__。访问对象原型的标准方法是 Object.getPrototypeOf()。
原型链继承是通过将子类的原型
对象指向父类的实例
来实现继承。
原型链继承:
- 原型链继承是通过将子类的原型对象指向父类的实例来实现继承。
javascriptfunction Parent() { this.name = "Parent"; } Parent.prototype.sayHello = function () { console.log("Hello, I am " + this.name); }; function Child() {} Child.prototype = new Parent(); // 将子类的原型对象指向父类的实例 var child = new Child(); child.sayHello(); // 输出 "Hello, I am Parent"
缺陷例子
原型链污染: 在原型链继承中,如果不小心修改了原型对象,那么所有继承自该原型的对象都会受到影响。这可能会导致意外的行为,特别是在多人协作或复杂代码中。
无法传递参数: 在使用原型链继承时,子类无法直接向父类构造函数传递参数,因为父类构造函数在子类原型链中,并不会在子类实例化时调用。这导致所有实例共享同一份父类属性,不能传入不同的参数。
不能完全重写父类方法: 如果尝试在子类中重写父类的方法,实际上只是在子类实例中创建了一个同名的新方法,而不是真正意义上的重写。这可能导致混淆和错误,因为子类的行为可能与预期的不同。
无法实现多重继承: JavaScript 的原型链只允许单一继承,无法直接实现多重继承,这在某些情况下可能会限制代码的组织和复用。
原型链污染:
js// 父类构造函数 function Parent() { this.colors = ["red", "blue", "green"]; } // 在父类原型中定义方法 Parent.prototype.sayHello = function () { console.log("Hello from Parent"); }; // 子类构造函数 function Child() {} // 使用原型链继承 Child.prototype = new Parent(); // 将子类的原型对象指向父类的实例 // 创建子类实例 var child = new Child(); var child2 = new Child(); // 修改 color child.colors.push("black"); // 修改父类原型中的方法 Parent.prototype.sayHello = function () { console.log("Modified Hello from Parent"); }; // 子类实例也受到了影响 child2.sayHello(); // 输出: Modified Hello from Parent console.log(child2.colors); // ["red", "blue", "green", "black"]
无法传递参数
js// 父类构造函数 function Parent(name) { this.name = name; } // 子类构造函数 function Child() {} // 使用原型链继承 Child.prototype = new Parent("Parent Name"); // 创建子类实例 var child = new Child(); console.log(child.name); // 输出: Parent Name
不能完全重写父类方法
js// 父类构造函数 function Parent() {} // 在父类原型中定义方法 Parent.prototype.sayHello = function () { console.log("Hello from Parent"); }; // 子类构造函数 function Child() {} // 使用原型链继承 Child.prototype = new Parent(); // 重写父类方法 Child.prototype.sayHello = function () { console.log("Hello from Child"); }; // 创建子类实例 var child = new Child(); // 子类实例调用重写后的方法 child.sayHello(); // 输出: Hello from Child
无法实现多重继承
js// 父类1构造函数 function Parent1() { this.name1 = "Parent1"; } // 父类2构造函数 function Parent2() { this.name2 = "Parent2"; } // 子类构造函数 function Child() {} // 使用原型链继承 Child.prototype = new Parent1(); // 尝试实现多重继承,但只能继承一个父类 Child.prototype = new Parent2(); // 覆盖了之前的继承 // 创建子类实例 var child = new Child(); console.log(child.name1); // 输出: undefined,无法访问另一个父类的属性 console.log(child.name2); // 输出: Parent2